package com.gopay.cashier.web.controller.T00100;

import com.gopay.cashier.common.exception.WebException;
import com.gopay.cashier.domain.bean.LoginUser;
import com.gopay.cashier.service.CaCertService;
import com.gopay.cashier.service.CertFreeQuotaService;
import com.gopay.cashier.service.PersonUsedQuotaService;
import com.gopay.cashier.service.SmsAcService;
import com.gopay.cashier.service.riskcontrol.CallRiskControlService;
import com.gopay.cashier.service.security.GopayDtCertService;
import com.gopay.cashier.web.command.BankPayChannelCommand;
import com.gopay.cashier.web.command.BankPayWay;
import com.gopay.cashier.web.command.ExpressPoundageVo;
import com.gopay.cashier.web.command.GopayChannelCommand;
import com.gopay.cashier.web.controller.BaseController;
import com.gopay.cashier.web.utils.BisBankBusinessProdConvertUtil;
import com.gopay.cashier.web.utils.CashierConfig;
import com.gopay.cashier.web.utils.CertFreeQuotaHelper;
import com.gopay.common.constants.SubAccountConstants;
import com.gopay.common.constants.cust.*;
import com.gopay.common.constants.microdone.EnumMicroScene;
import com.gopay.common.constants.proccode.ProcCodeConstants;
import com.gopay.common.constants.trans.*;
import com.gopay.common.constants.txncd.IntTxnCd;
import com.gopay.common.cps.dao.order.CpsGeneralReceiptOrderQueryDAO;
import com.gopay.common.cps.dao.trans.CpsReceiptSplitDtlQueryDAO;
import com.gopay.common.domain.UserInfo;
import com.gopay.common.domain.acps.AcctStatus;
import com.gopay.common.domain.acps.FrezCode;
import com.gopay.common.domain.acps.model.AcctMastBean;
import com.gopay.common.domain.cashier.PayDoneResult;
import com.gopay.common.domain.cashier.PayWay;
import com.gopay.common.domain.cps.CpsGenMainOrder;
import com.gopay.common.domain.cps.CpsGenReceiptOrder;
import com.gopay.common.domain.cps.CpsReceiptSplitDtl;
import com.gopay.common.domain.cust.CustCaCert;
import com.gopay.common.domain.cust.CustCertFreeQuota;
import com.gopay.common.domain.cust.CustCorpInfo;
import com.gopay.common.domain.cust.CustPersonInfo;
import com.gopay.common.domain.poundage.PoundageRes;
import com.gopay.common.domain.user.UserPayPwdResult;
import com.gopay.common.domain.user.identify.vo.PersonTypeQuotaVo;
import com.gopay.common.exception.GopayException;
import com.gopay.common.security.vo.DtCertCheckParamVO;
import com.gopay.common.security.vo.DtCertCheckResultVO;
import com.gopay.common.user.manager.PersonIdentifyManager;
import com.gopay.common.util.DateUtils;
import com.gopay.common.util.PwdControlUtil;
import com.gopay.common.util.ReflectionUtil;
import com.gopay.common.util.RequestUtils;
import com.gopay.remote.order.MainOrderField;
import com.gopay.remote.order.Tran01813OrderCheckAndUpdateRemoteService;
import net.sf.json.JSONObject;
import ocx.AESWithJCE;
import org.apache.commons.lang3.StringUtils;
import org.apache.shiro.SecurityUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

/**
 * Created by HJY on 2015/5/5.
 * 网关支付 银行卡支付
 * 支付确认 差额支付 国付宝账户支付
 */
@Controller
@RequestMapping("/sec")
public class PayConfirm00100Controller extends BaseController {
    protected static final String PORTAL_URL = CashierConfig.get(CashierConfig.PORTAL_URL);
    protected static final String CAS_URL = CashierConfig.get(CashierConfig.CAS_SERVER_URL);
    
    @Resource(name="callRiskControlService")
    private CallRiskControlService callRiskControlService;
    
//    @Resource(name="certCheckClient")
//    private CertCheckRemoteServiceBak certCheckClient;

    @Resource(name = "caCertService")
    private CaCertService caCertService;
    
	@Resource(name = "personIdentifyManager")
    private PersonIdentifyManager personIdentifyManager;
    
    @Resource(name = "personIdUsedQuotaService")
    private PersonUsedQuotaService personIdUsedQuotaService;
    
    @Resource(name="certFreeQuotaService")
    private CertFreeQuotaService certFreeQuotaService;

    @Autowired
    private CpsReceiptSplitDtlQueryDAO cpsReceiptSplitDtlQueryDAO;

    @Resource(name = "tran01813OrderCheckAndUpdateService")
    private Tran01813OrderCheckAndUpdateRemoteService tran01813OrderCheckAndUpdateRemoteService;
    
    @Resource(name="certFreeQuotaHelper")
    private CertFreeQuotaHelper certFreeQuotaHelper;
    private @Value("#{webProperties['portal.url']}") String portalUrl;
    
    /**
     * 短信认证接口
     */
    @Resource(name="smsAcService")
    private SmsAcService smsAcService;

    @Resource(name = "gopayDtCertService")
    private GopayDtCertService gopayDtCertService;

    @Autowired
    private CpsGeneralReceiptOrderQueryDAO cpsGeneralReceiptOrderQueryDAO;



    @RequestMapping(value = "/00100/pay/confirm.shtml")
    public ModelAndView execute(BankPayChannelCommand bankCommand,GopayChannelCommand gopayCommand,HttpServletRequest request) throws GopayException {
        printRequest("PayConfirm00100Controller--登录后confirm,command="+bankCommand);
        //add by fanghw 20160524
        if(StringUtils.isNotBlank(bankCommand.getPayBankCodeAll())){
            String selBankCode=bankCommand.getPayBankCodeAll().split("-")[1];
            if(PayChannel._01.value.equals(bankCommand.getPayChannel())){
                bankCommand.setPersonalPayBankCode(selBankCode);
            }else if(PayChannel._51.value.equals(bankCommand.getPayChannel())){
                bankCommand.setCorpPayBankCode(selBankCode);
            }
        }
        if(bankCommand.getPayWay() == BankPayWay.S){
            throw new GopayException("不支持差额支付！");
        }
        if(bankCommand.getPayWay() == BankPayWay.F){
            //登录后网银支付
            return submit(bankCommand,gopayCommand,request);
        }else{
            //余额、差额支付
            return balPay(bankCommand,gopayCommand);
        }
    }

    /**
     * 个人用户  类别 限额 页
     * @return
     * @throws WebException
     */
    @RequestMapping(value = "/00100/pay/userQuota.shtml")
    public ModelAndView userQuota() throws WebException{
        LoginUser loginUser = getLoginUser();
        UserInfo userInfo = loginUser.getUser();
        
        if(!UserInfoConstants.USER_TYPE_PERSON.equals(userInfo.getUserType())){
            throw new WebException("用户类别有误！");
        }
        
        ModelAndView mav = new ModelAndView("/00100/content/acct/userQuota");
        
        //调用service查询个人账户额度信息
        PersonTypeQuotaVo personTypeQuota = 
                personIdUsedQuotaService.findPersonTypeQuota(userInfo.getCustId());
        mav.addObject("personTypeQuota", personTypeQuota);
        
        return mav;
    }

    private ModelAndView balPay(BankPayChannelCommand bankCommand,GopayChannelCommand gopayCommand) throws GopayException {
        printRequest();
        //充值订单
        CpsGenMainOrder order = getMainOrder(getRequest().getParameter(GOPAY_ORDER_ID), true);
        // 验证
        if(!validate(bankCommand,gopayCommand, order)){
            return next(order,bankCommand, gopayCommand);
        }
        return next(order,bankCommand,gopayCommand);
    }

    
    /**
     * 校验数字证书
     * @return
     */
    @RequestMapping(value = "/caCert/checkCaCert.shtml", method = RequestMethod.POST)
    @ResponseBody
    public String checkCaCert() {
        JSONObject json = new JSONObject();
        String stat;
        String sn;
        LoginUser oprInfo = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        String custId = oprInfo.getUser().getCustId();
        CustCaCert custCaCert = caCertService.getCustCaCertByCustId(custId);
        //该客户未注册数字证书
        if (null == custCaCert) {
            stat = "00";
        } else {
            stat = custCaCert.getStat();
            // 客户未关闭证书，获取客户证书sn
            if (!"02".equals(stat)) {
                sn = custCaCert.getSn();
                Long sign = 1455935280535L;//System.currentTimeMillis();

                json.accumulate("sn", sn);
                // 证书验签需要
                json.accumulate("sign", sign);
                json.accumulate("portalUrl", portalUrl);
            }
        }

        json.accumulate("stat", stat);
        System.out.println(json.toString());
        return json.toString();
    }

    @RequestMapping(value = "/00100/pay/submit.shtml")
    public ModelAndView submit(BankPayChannelCommand bankCommand,GopayChannelCommand gopayCommand,HttpServletRequest request) throws GopayException {

        printRequest();
        LoginUser oprInfo = (LoginUser) SecurityUtils.getSubject().getPrincipal();
        //充值订单
        String orderId = getRequest().getParameter(GOPAY_ORDER_ID);
        String mcryptKey = "";
        String status = ProcCodeConstants.PROC_CODE_000S1000;
        try {
            if (bankCommand.getPayWay() != BankPayWay.F && !StringUtils.equals(bankCommand.getAntiPhish(),"1")){
                mcryptKey = (String) getRequest().getSession().getAttribute("mcrypt_key");
                getRequest().getSession().removeAttribute("mcrypt_key");
                if(StringUtils.isBlank(mcryptKey)){
                    throw new GopayException(ProcCodeConstants.PROC_CODE_100E5120, "浏览器刷新后，请重新输入密码");
                }
                if (StringUtils.isEmpty(gopayCommand.getPayPassword())){
                    gopayCommand.setPayPassword(getRequest().getParameter("password"));
                }
            }
            CpsGenMainOrder order = getMainOrder(orderId, true);

            String custId = oprInfo.getUser().getCustId();
            String gopayAcctId = request.getParameter("gopayAcctId");
//        String sign = request.getParameter("sign");
            String signedData = request.getParameter("signedData");

            // 只有账户支付才校验数字证书  dak.wang  20160524
            //add by zhuliang at 2016-7-11 不是账户免验证标识，进行数字证书签名验签
//        String  freeFlag =getRequest().getParameter("freeFlag");
            //验签时需要再次判断是否免验，防止表单窜改
            BigDecimal payAmt = order.getMerTxnAmt();
//        boolean quotaFlag=certFreeQuotaHelper.checkFreeQuota(payAmt, custId);
//        String pwd = gopayCommand.getPayPassword();
//        if (!StringUtils.isBlank(pwd)&&!quotaFlag) {
//            try {
//                certCheckClient.checkCert(sign, signedData,custId );
//            } catch (GopayException e) {
//                String errCode = e.getErrCode();
//                logger.error("数字证书校验失败" + sign + ", " + signedData, e);
//                throw new WebException(errCode, e);
//            }
            if(bankCommand.getPayWay() != BankPayWay.F) {
                //------校验数字证书和动态口令------start    edit by fanghw 20160923
                //封装令牌和证书校验参数VO
                DtCertCheckParamVO dccParamVo = new DtCertCheckParamVO();
                dccParamVo.setUserId(oprInfo.getUser().getUserId());
                dccParamVo.setCustId(custId);
                dccParamVo.setCertSignValue(signedData);
                dccParamVo.setDtCode(request.getParameter("dcpass"));
                dccParamVo.setTranAmt(payAmt);

                //校验令牌和证书
                DtCertCheckResultVO dccResultVo = gopayDtCertService.checkDtCert(request, dccParamVo);
                if (!dccResultVo.isSuccess()) {
                    throw new GopayException(dccResultVo.getErrCode(), dccResultVo.getErrMsg());
                }
                //------校验数字证书和动态口令------end
            }
//        }
            //校验当前登录用户是否通过实名认证  add by fanghw 20151113
            if(bankCommand.getPayWay() != BankPayWay.F){
                checkPayCustRealNameCertify(getLoginUser());
            }

            // 验证
            if(!validateSubmit(bankCommand, gopayCommand, order,mcryptKey)){
                logger.error("账户余额付款确认进行密码验证失败，执行nex方法");
                status = bankCommand.getErrMsg();
                return next(order,bankCommand, gopayCommand);
            }
            //防钓鱼校验
            ModelAndView check = checkAntiPhish(bankCommand,"/sec/00100/pay/submit.shtml?orderKey="+getRequest().getParameter("orderKey")+"&orderId="+orderId);
            if(check != null){
                status = "防钓鱼校验未通过";
                return check;
            }
            updateOrder(bankCommand,order);
            order = getMainOrder(orderId, true);

            //三类个人账号余额支付校验
            if(UserType.Person.value.equals(oprInfo.getUser().getUserType()) && (BankPayWay.A.equals(bankCommand.getPayWay()))){
                checkThreeAcct(oprInfo.getUser().getUserId(), oprInfo.getUser().getCustId(), order.getMerTxnAmt());
            }

            if(bankCommand.getPayWay() != BankPayWay.A){//非余额全额支付
                /**** add by sh.jiao 20170920 增加云账户子账户收款修改关联订单交易金额，手续费金额等字段更新逻辑 start ****/
                /*if(IntTxnCd._01813.value.equals(order.getGopayIntTxnCd())) {
                    String resultCode = tran01813OrderCheckAndUpdateRemoteService.checkAndUpdateOrder(order.getGopayOrderId());
                    if (!ProcCodeConstants.PROC_CODE_000S1000.equals(resultCode)) {
                        throw new GopayException(resultCode);
                    }
                }*/
                /**** add by sh.jiao 20170920 增加云账户子账户收款修改关联订单交易金额，手续费金额等字段更新逻辑 end ****/
                updateOrderProcess(order);
                //rimsProcess(order);
                //调用风控二期服务校验 add by xuhui 20160811
                callRiskControlService.assess(order.getGopayOrderId(), order.getPayChannel(), null, null);
                return bankPay(order);
            }else{
                //rimsProcess(order);
                //调用风控二期服务校验 add by xuhui 20160811
                callRiskControlService.assess(order.getGopayOrderId(), order.getPayChannel(), null, null);
                /**** add by sh.jiao 20170920 增加云账户子账户收款修改关联订单交易金额，手续费金额等字段更新逻辑 start ****/
                /*if(IntTxnCd._01813.value.equals(order.getGopayIntTxnCd())) {
                    String resultCode = tran01813OrderCheckAndUpdateRemoteService.checkAndUpdateOrder(order.getGopayOrderId());
                    if (!ProcCodeConstants.PROC_CODE_000S1000.equals(resultCode)) {
                        throw new GopayException(resultCode);
                    }
                }*/
                /**** add by sh.jiao 20170920 增加云账户子账户收款修改关联订单交易金额，手续费金额等字段更新逻辑 end ****/
                completeOrder(order);
                return new ModelAndView("redirect:/00100/express/progress.shtml?orderKey="+getRequest().getParameter("orderKey")+"&t=0&orderId="+orderId);
            }
        } catch (GopayException e) {
            status = e.getErrMsg()==null?e.getErrCode():e.getErrMsg();
            throw e;
        }finally {
            try {
                if (bankCommand.getPayWay() != BankPayWay.F && !StringUtils.equals(bankCommand.getAntiPhish(),"1")){
                    logMicrodone(getRequest(),mcryptKey, EnumMicroScene.CASHIER_BALANCE_PAY.getCode(),orderId,status,oprInfo.getUser());
                }
            } catch (Exception e1) {
                logger.error("账户余额付款确认支付密码控件记录入库异常",e1);
            }
        }
    }


    private String completeOrder(CpsGenMainOrder order) throws GopayException {
        PayDoneResult r = new PayDoneResult();
        r.setSuccess(true);
        r.setPayWay(PayWay.AcctPay);
        r.setOrderId(order.getGopayOrderId());
        //支付方式
        String payType=PayAuthType.one.value;//支付密码
//        if(userDcPwdManager.getDCAuth(order.getPayCustId())){ //支付密码+其他(动态口令卡)
        if(userDcPwdManager.getDCAuthbyUserId(order.getUserId())){ //支付密码+其他(动态口令卡)
            payType=PayAuthType.three.value;
        }else{//支付密码+数字证书(电子签名)的校验
            CustCaCert custCaCert = caCertService.getCustCaCertByCustId(order.getPayCustId());
            if(null != custCaCert && CustCaCertConstants.CUST_CA_CERT_STAT_ACTIVE.equals(custCaCert.getStat())){
                payType=PayAuthType.two.value; 
            }
        }  
        CustCertFreeQuota custCertFreeQuota = certFreeQuotaService.getByCustId(order.getPayCustId());

        r.setPayType(payType);
        //支付方式结束
        String result = cashierPayCallbackService.finish(r);
        return result;
    }

    private BankPayChannelCommand saveInchargeOrder(BankPayChannelCommand command,CpsGenMainOrder order) throws WebException {
        BankPayChannelCommand inchargeCommand = new BankPayChannelCommand();
        ReflectionUtil.copyProperties(inchargeCommand, command);
        String inchargeOrderId = "";
        PayChannel payChannel = PayChannel.get(command.getPayChannel());
        // 计算银行卡实际支付金额，如果是全额支付，则为订单金额；如果是差额支付，则为订单金额减去账户可用余额
        BigDecimal actualPayAmt = getActualPayAmt(command, order);
        LoginUser user = getLoginUser();
        String custId = (null == user || null == user.getUser()) ? "-" : user.getUser().getCustId();
        try {
            logger.error("调用cps创建支付充值订单.BEGIN.call cps for saving incharge order." + command);
            inchargeOrderId = cashierPayCallbackService.saveInchargeOrder(order.getGopayOrderId(),actualPayAmt.toString(), payChannel.value, command.getPayBankCode(), custId);
            logger.error("调用cps创建支付充值订单.END.call cps for saving incharge order." + inchargeOrderId + ", " + command);
        } catch (GopayException e) {
            logger.error("调用cps创建充值订单发生错误！shortfallpay saveInchargeOrder error!" + command, e);
            throw new WebException(e.getErrCode());
        }
        inchargeCommand.setInChargeOrderId(inchargeOrderId);
        return inchargeCommand;
    }

    private  ModelAndView next(CpsGenMainOrder order,BankPayChannelCommand bankCommand,GopayChannelCommand gopayCommand) throws WebException {
        ModelAndView mav = new ModelAndView("/00100/content/acct/payConfirm");
        BankPayWay payWay = bankCommand.getPayWay();
        mav.addObject("payWay",payWay.toString());

        DecimalFormat df = new DecimalFormat("0.00");
        BigDecimal payAmt = order.getMerTxnAmt();
        if(payWay == BankPayWay.S){//差额支付
            BigDecimal bankPayAmt = getActualPayAmt(bankCommand, order);
            BigDecimal acctPayAmt = order.getMerTxnAmt().subtract(bankPayAmt);
            mav.addObject("bankPayAmt", df.format(bankPayAmt));
            mav.addObject("acctPayAmt", df.format(acctPayAmt));
            mav.addObject("payChannel",bankCommand.getPayChannel());
            mav.addObject("payBankCode",bankCommand.getPayBankCode());
        }else if(payWay == BankPayWay.A){
            mav.addObject("acctPayAmt", df.format(payAmt));
        }
        mav.addObject("payAmt", df.format(payAmt));
        mav.addObject("order", getOrderInfo(order.getGopayOrderId()));
        mav.addObject("orderId", order.getGopayOrderId());
        mav.addObject("gopayAcctId", gopayCommand.getGopayAcctId());
        mav.addObject("formhash", setReqAttr(KEY_FORM_HASH, getRandom(32)));// 防止hack
        mav.addObject("portal_url",PORTAL_URL);
        mav.addObject("cas_server_url", CAS_URL);
        mav.addObject("temp",bankCommand);
        // 增加校验使用动态口令卡的权限
		String custId = getLoginUser().getUser().getCustId();
        String userId = getLoginUser().getUser().getUserId();
//		boolean flag = userDcPwdManager.getDCAuthbyUserId(userId);
        //动态口令、数字证书免验限额 add by gaocl 20160711 ----start
  //      boolean quotaFlag=certFreeQuotaHelper.checkFreeQuota(payAmt, custId,userId);
  //      String freeFlag = "";
  //      if(quotaFlag){
  //          freeFlag ="01";
  //      }
 //       mav.addObject("freeFlag", freeFlag);
        //动态口令、数字证书免验限额 add by gaocl 20160711 ----end 
//        if (flag && quotaFlag) {
//			mav.addObject("haveDcAuth", "1");// 1表示有吧
//		}
		// end
        //---------start----ssj----短信认证-2016/08/22-----------
        Map<String,String> mapSmsAc=smsAcService.getSmsAc(getLoginUser());
        mav.addObject("smsAcStat",mapSmsAc.get("smsAcStat"));
        mav.addObject("userType",mapSmsAc.get("userType"));
        //---------end----ssj----短信认证------------
        
        return mav;
    }

    private  ModelAndView bankPay(CpsGenMainOrder order) throws WebException {
        String orderDate = DateUtils.format(order.getGopayTxnTm());
        /**系统加固   发送BIS交易金额  1.首先获取结算金额  2.结算金额无值，取总金额     zhg.zhang 20160712 start**/
        
        BigDecimal amount=order.getSettleAmt()!=null
        		&&BigDecimal.ZERO.compareTo(order.getSettleAmt())<0
        		?order.getSettleAmt():order.getTotalOrderAmt();
        logger.info("order settleAmt="+order.getSettleAmt()+""
        		+ ",totalOrderAmt="+order.getTotalOrderAmt()+",orderId="+order.getGopayOrderId());
        /**系统加固   发送BIS交易金额  1.首先获取结算金额  2.结算金额无值，取总金额     zhg.zhang 20160712 end**/
        
        //BigDecimal amount = order.getTotalOrderAmt(); 根据上面的取，注释掉原代码
        String bank = order.getOutStlmId();
        String payChannel = order.getPayChannel();

        getRequest().getSession().removeAttribute(CAS_GOPAY_USER);
        ModelAndView mav = new ModelAndView("pay/bankPayForBis");
        mav.addObject("orderId", order.getGopayOrderId());
        mav.addObject("amount", amount.toString());
        mav.addObject("orderDate", orderDate);
        mav.addObject("userType", "");
        mav.addObject("bank", bank);
        mav.addObject("bisUrl", CashierConfig.get(CashierConfig.BIS_URL));
        mav.addObject("bankBusProd", BisBankBusinessProdConvertUtil.getBisBankBusinessProd(PayChannel.get(payChannel)).value);

        setB2BBankConfig(mav,PayChannel.get(payChannel),bank);
        return mav;
    }

    private void updateOrder(BankPayChannelCommand command, CpsGenMainOrder order) throws WebException {
        Map<MainOrderField, String> values = new HashMap<MainOrderField, String>();
        LoginUser loginUser = getLoginUser();
        //计算手续费
        ExpressPoundageVo epv = getPoundageRes(order,command);
        PayChannel payChannel = epv.getPayChannel();
        PoundageRes p = epv.getPoundageRes();

        if(loginUser!=null){
            values.put(MainOrderField.PAY_CUST_ID, loginUser.getUser().getCustId());
            if ( PayChannel._02.value.equals(payChannel.toString()) || PayChannel._52.value.equals(payChannel.toString()) ){
                values.put(MainOrderField.PAY_ACCT, command.getGopayAcctId());//账户支付才更新PAY_ACCT
            }
        }
        values.put(MainOrderField.PAY_CHANNEL, payChannel.toString());
        values.put(MainOrderField.OUT_STLM_ID, command.getPayBankCode());
        values.put(MainOrderField.ORDER_DEAL_AMT, p.getOrderDealAmt().toString());
        values.put(MainOrderField.ORDER_REAL_FEE_AMT, p.getOrderRealFeeAmt().toString());
        values.put(MainOrderField.TOTAL_ORDER_AMT, p.getTotalAmt().toString());
        values.put(MainOrderField.TOTAL_ORDER_FEE_AMT, p.getTotalFeeAmt().toString());
        values.put(MainOrderField.ORDER_FEE_PAYER, p.getOrderFeePayer().value);
        values.put(MainOrderField.TXN_STA_CD, TxnStaCode.TXN_STA_CD_30101.value + "");
        
        /**结算金额： 网银付款更新结算金额字段  系统加固   zhg.zhang 20160712 start**/
        values.put(MainOrderField.SETTLE_AMT, p.getSettleAmt().toPlainString());
        /**结算金额： 网银付款更新结算金额字段  系统加固   zhg.zhang 20160712 end**/

        /**远程IP地址 songefengli 20160922**/
        values.put(MainOrderField.REMOTE_IP, RequestUtils.getRemoteRealIpAddr(getRequest()));

        // 如果是收款方承担手续费，且手续费金额大于订单金额，中断交易，防止实际交易金额为负数。
        if (OrderFeePayer.REC_PAYER.equals(p.getOrderFeePayer())) {
            if (1 == p.getTotalFeeAmt().compareTo(order.getMerTxnAmt())) {
                logger.error("手续费金额大于订单金额，中断交易！pay error: feeAmt[" + p.getTotalFeeAmt() + "]>merTxnAmt["
                        + order.getMerTxnAmt() + "]! " + command + ", " + order);
                throw new WebException(ProcCodeConstants.PROC_CODE_100E5055);
            }

            /*通用分账  added by Chenyu Li at 2018/3/10 start*/
            if(isSplit(order)){
                CpsReceiptSplitDtl cpsReceiptSplitDtl = cpsReceiptSplitDtlQueryDAO.queryPlatformDtlsByGopayOrderId(order.getGopayOrderId());
                if (cpsReceiptSplitDtl == null) {
                    logger.error("平台方没有参与分账，中断交易！pay error: feeAmt[" + p.getTotalFeeAmt() + "]>merTxnAmt["
                            + order.getMerTxnAmt() + "]! " + command + ", " + order);
                    throw new WebException(ProcCodeConstants.PROC_CODE_100E1033);
                }
                if (1 == p.getTotalFeeAmt().compareTo(cpsReceiptSplitDtl.getMerTxnAmt())) {
                    logger.error("手续费金额大于平台方分账金额，中断交易！pay error: feeAmt[" + p.getTotalFeeAmt() + "]>merTxnAmt["
                            + order.getMerTxnAmt() + "]! " + command + ", " + order);
                    throw new WebException(ProcCodeConstants.PROC_CODE_100E1405);
                }
            }
            /*通用分账  added by Chenyu Li at 2018/3/10 end*/
        }

        // 云账户子账户收款交易如果普通账户可用余额小于手续费，则抛出异常，账户余额不足 add by sh.jiao 20171020
        if(IntTxnCd._01813.value.equals(order.getGopayIntTxnCd())) {
            AcctMastBean acct = acctTransService.getAccount(order.getMainRecvAcct());
            if(acct == null) {
                logger.error("收款账户不存在,gopayOrderId:"+order.getGopayOrderId());
                throw new WebException(ProcCodeConstants.PROC_CODE_100E5260);
            }
            if (new BigDecimal(acct.getAvaAmt()).compareTo(p.getTotalFeeAmt())<0){
                logger.error("手续费金额大于普通账户可用余额，中断交易，支付失败，请联系平台！pay error: feeAmt[" + p.getTotalFeeAmt() + "]>avaAmt["
                        + acct.getAvaAmt() + "]! " + command + ", " + order);
                throw new WebException(ProcCodeConstants.PROC_CODE_100E5344);
            }
        }

        try {
            logger.error("调用cps更新订单状态.BEGIN.call cps update mainOrder." + command + ", " + order + ", " + values);
            mainOrderUpdateService.payUpdate(order.getGopayOrderId(), values);
            logger.error("调用cps更新订单状态.END.call cps update mainOrder." + command + ", " + order);
        } catch (GopayException e) {
            logger.error("调用cps更新订单状态出错！call cps update mainOrder exception!" + command + ", " + order, e);
            throw new WebException(e.getErrCode());
        }
    }

    private void updateOrderProcess(CpsGenMainOrder order) throws WebException {
        Map<MainOrderField, String> values = new HashMap<MainOrderField, String>();
        values.put(MainOrderField.TXN_STA_CD, TxnStaCode.TXN_STA_CD_30101.value + "");
        try {
            mainOrderUpdateService.updateMany(order.getGopayOrderId(), values);
        } catch (GopayException e) {
            throw new WebException(e.getErrCode());
        }
    }

    private boolean validate(BankPayChannelCommand command,GopayChannelCommand gopayCommand, CpsGenMainOrder order) throws GopayException {
        HttpServletRequest request = getRequest();
        LoginUser loginUser = getLoginUser();
        if(loginUser == null){
            throw new WebException(ProcCodeConstants.PROC_CODE_100W1006);
        }
        if(command.getPayWay() != BankPayWay.A){
            if (StringUtils.isBlank(command.getPayBankCode())) {
                logger.error(this.getClass() + "没有选择银行！ no bank selected!!" + command);
                throw new WebException(ProcCodeConstants.PROC_CODE_200E1001);
            }
            if (StringUtils.isBlank(command.getPayChannel())) {
                logger.error(this.getClass() + "没有选择银行类型！ no paychannel selected!!" + command);
                throw new WebException(ProcCodeConstants.PROC_CODE_200E1001);
            }
        }

        if (null == order) {
            logger.error("找不到订单！order not exits!" + command);
            throw new WebException(ProcCodeConstants.PROC_CODE_100E5041);
        }
        if (TxnStaCode.TXN_STA_CD_30000.value != (order.getTxnStaCd())) {
            logger.error("订单状态不对！txn_sta_cd wrong!" + order);
            throw new WebException(ProcCodeConstants.PROC_CODE_100E5042);
        }
        if(StringUtils.equals(loginUser.getUser().getCustId(), order.getMainRecvCustId()) || (StringUtils.isNotBlank(command.getGopayAcctId()) && StringUtils.equals(command.getGopayAcctId(), order.getMainRecvAcct()))){
            throw new WebException(ProcCodeConstants.PROC_CODE_100E5011);
        }
        UserInfo userInfo = loginUser.getUser();
        if (null == userInfo || UserInfoConstants.USER_STAT_CANCEL.equals(userInfo.getUserStat())) {
            logger.error("用户不存在或尚未登录！user not exist or not login! " + request.getRemoteUser());
            throw new WebException(ProcCodeConstants.PROC_CODE_100E2001);
        }
        if (!UserInfoConstants.USER_STAT_NORMAL.equals(userInfo.getUserStat())) {
            logger.error("用户状态异常：" + userInfo.getCustId());
            throw new WebException(ProcCodeConstants.PROC_CODE_100E2002);
        }
        String userType = userInfo.getUserType();
        if (UserInfoConstants.USER_TYPE_PERSON.equals(userType)) {
            CustPersonInfo info = custPersonInfoQueryManager.get(userInfo.getCustId());
         // 状态99 并且 步骤19为假注销  dak.wang  20160530  start
//          if (info == null || CustPersonInfoConstants.CUST_STAT_CANCEL.equals(info.getCustStat())) {
          if (info == null) {
          
              throw new WebException(ProcCodeConstants.PROC_CODE_100E5001);
          }
          if (!CustPersonInfoConstants.CUST_STAT_NORMAL.equals(info.getCustStat()) 
                  && !RealNameCertifyStep.REAL_NAME_CERTIFY_STEP_19.value.equals(info.getRealNameCertifyStep())) {
              throw new WebException(ProcCodeConstants.PROC_CODE_100E5002);
          }
       // end
        } else if (userType.startsWith("2")) {
            CustCorpInfo info = custCorpInfoService.get(userInfo.getCustId());
            if (info == null || CustCorpInfoConstants.CORP_STAT_CANCEL.toString().equals(info.getCorpStat())) {
                throw new WebException(ProcCodeConstants.PROC_CODE_100E5001);
            }
            if (!CustCorpInfoConstants.CORP_STAT_NORMAL.toString().equals(info.getCorpStat())) {
                throw new WebException(ProcCodeConstants.PROC_CODE_100E5002);
            }
        } else {
            throw new WebException(ProcCodeConstants.PROC_CODE_100E1027);
        }

        //校验收款方
        checkRecvCustStatus(0, order.getMainRecvCustId());
        AcctMastBean acct = acctTransService.getAccount(order.getMainRecvAcct());
        if (null == acct) {
            logger.error("账户不存在,acctId=" + order.getMainRecvAcct());
            throw new WebException(ProcCodeConstants.PROC_CODE_100E6012);
        }
        if (AcctStatus.F.equals(acct.getAccStatus())) {
            if (FrezCode.CRE.equals(acct.getFrezCode()) || FrezCode.FUL.equals(acct.getFrezCode())) {
                throw new GopayException(ProcCodeConstants.PROC_CODE_100E3025, "账户[" + order.getMainRecvAcct()
                        + "]处于冻结状态[" + acct.getFrezCode() + "]，无法入款");
            }
        }
        return true;
    }

    private boolean validateSubmit(BankPayChannelCommand command,GopayChannelCommand gopayCommand, CpsGenMainOrder order,String mcryptKey) throws GopayException {
        boolean resCheck = validate(command,gopayCommand,order);
        if(resCheck && command.getPayWay() != BankPayWay.F && !StringUtils.equals(command.getAntiPhish(),"1")){
            String payPwd;
            try {
//                payPwd = PwdControlUtil.decryptPwd(getRequest(), gopayCommand.getPayPassword());
                payPwd = AESWithJCE.getResult(mcryptKey, gopayCommand.getPayPassword());//调用解密接口.获得密码明文。
            } catch (Exception e) {
                logger.error("密码解密发生错误！！ Error occurs while decrypting password!!" + command, e);
                command.setErrId("1");
                command.setErrMsg("密码解密发生错误");
                return false;
            }
            UserPayPwdResult res = userPayPwdManager.verifyPayPwd(getLoginUser().getUser().getUserId(), payPwd);
            if(res == null || !res.isVerifySuccess()){
                command.setErrMsg(res==null ? "支付密码校验失败":res.getErrorMsg());
                command.setErrId("1");
                return false;
            }
            
            //校验动态口令卡
    //        String custId=getLoginUser().getUser().getCustId();
    //        String userId=getLoginUser().getUser().getUserId();
            //boolean flag = userDcPwdManager.getDCAuth(custId);
    //        boolean flag = userDcPwdManager.getDCAuthbyUserId(userId);
            //数字证书、动态口令免验限额 add by gaocl 20160711 ----start
    //         BigDecimal tranAmt =order.getMerTxnAmt();
    //         boolean quotaFlag=certFreeQuotaHelper.checkFreeQuota(tranAmt, custId);
              //----end 
    //         if (flag && quotaFlag) {// 有使用的才校验
    //			String dcPass = getRequest().getParameter("dcpass");
   // 			String dcErrMesg="";
    //			try {
    				//dcErrMesg = userDcPwdManager.getErrMesg(custId, dcPass);
   // 			    dcErrMesg = userDcPwdManager.getErrMesg(userId, dcPass);
   // 			} catch (Exception e) {
    				// TODO Auto-generated catch block
   // 				command.setDcErrMesg("校验动态口令卡出现异常");
   // 				 return false;
    //			}
    			
    //			if (!"".equals(dcErrMesg)) {
    //				command.setDcErrMesg(dcErrMesg);
    //				 return false;
    //			}

    //		}
             //-------------------star-------ssj 2016/8/22新增短信认证功能-----------------------------------
				if (smsAcService.canSendSms(getLoginUser())) {// 开启短信认证 切 短信认证状态正常
					try {
						String smsAcVerifyCode = getRequest().getParameter("smsAcVerifyCode");
					    smsAcService.checkPayPwdAndVerifyCode(getLoginUser(), smsAcVerifyCode);
					} catch (Exception e) {
						command.setErrId("2");
						command.setErrMsg(e.getMessage());
						return false;
					}

				}
			//-------------------end-------ssj 2016/8/22新增短信认证功能-----------------------------------
            
            
        }
        return  true;
    }

    private PayChannel getPayChannel(){
        PayChannel payChannel = null;
        LoginUser loginUser = getLoginUser();
        if(loginUser!=null){
            UserType userType = UserType.get(loginUser.getUser().getUserType());
            if (UserType.Person.equals(userType)) {
                payChannel = PayChannel._02;
            } else {
                payChannel = PayChannel._52;
            }
        }
        return payChannel;
    }

    /**
     * 计算正确的差额支付金额，同时进行校验
     */
    private BigDecimal getActualPayAmt(BankPayChannelCommand command, CpsGenMainOrder order) throws WebException {
        if (command.isShortfallPay()) {
            BigDecimal orderAmt = order.getMerTxnAmt();
            AcctMastBean acct = acctTransService.getAccount(command.getGopayAcctId());
            if (null == acct) {
                logger.error("账户不存在！acctMast not exist!" + command + ", " + order);
                throw new WebException(ProcCodeConstants.PROC_CODE_000E3001);
            }
            BigDecimal acctBalance = new BigDecimal(acct.getAvaAmt());
            //账户可用余额 + 差额支付金额 = 订单金额
            if(orderAmt.compareTo(acctBalance)==1){
                BigDecimal shortfallPayAmt = orderAmt.subtract(acctBalance);
                return shortfallPayAmt;
            }
        }
        return order.getMerTxnAmt();
    }

    protected ExpressPoundageVo getPoundageRes(CpsGenMainOrder order,BankPayChannelCommand command) throws WebException {
        ExpressPoundageVo vo  = new ExpressPoundageVo();
        LoginUser user = getLoginUser();
        //add by jianghoup 增加单银行特例手续费中的银行代码 20160908
        String bankCode =null;
        logger.info("付款通道为："+command.getPayChannel());
        if(PayChannel._01.value.equals(command.getPayChannel())){
            bankCode = command.getPersonalPayBankCode();
        }else if(PayChannel._51.value.equals(command.getPayChannel())){
            bankCode = command.getCorpPayBankCode();
        }
        logger.info("增加特例银行，编码为："+bankCode);

        if(user == null){
            if(command.getPayWay() != BankPayWay.A && command.getPayChannel() != null){
                PayChannel payChannel = PayChannel.get(command.getPayChannel());
                vo.setPayChannel(payChannel);
                vo.setPoundageRes(getPoundageRes(order, payChannel,bankCode));
                return vo;
            }
        }else{
            PayChannel payChannel1 = getPayChannel();
            PoundageRes res1 = getPoundageRes(order, payChannel1,bankCode);
            vo.setPayChannel(payChannel1);
            vo.setPoundageRes(res1);
            if(command.getPayWay() != BankPayWay.A && command.getPayChannel() != null){
                PayChannel payChannel2 =  PayChannel.get(command.getPayChannel());
                PoundageRes res2 = getPoundageRes(order, payChannel2,bankCode);
                int comp = res1.getTotalFeeAmt().compareTo(res2.getTotalFeeAmt());
                if(comp ==-1 || comp ==0 || command.getPayWay() == BankPayWay.F ){
                    vo.setPayChannel(payChannel2);
                    vo.setPoundageRes(res2);
                }
            }
            return  vo;
        }
        throw new WebException(ProcCodeConstants.PROC_CODE_100E5051);
    }
    
    //三类账号网关支付余额支付验证
    private void checkThreeAcct(String userId,String custId,BigDecimal orderAmt) throws WebException {
        String payType=PayAuthType.one.value;//支付密码
//        if(userDcPwdManager.getDCAuth(custId)){ //支付密码+其他(动态口令卡)
        if(userDcPwdManager.getDCAuthbyUserId(userId)){ //支付密码+其他(动态口令卡)
            payType=PayAuthType.three.value;
        }else{//支付密码+数字证书(电子签名)的校验
            CustCaCert custCaCert = caCertService.getCustCaCertByCustId(custId);
            if(null != custCaCert && CustCaCertConstants.CUST_CA_CERT_STAT_ACTIVE.equals(custCaCert.getStat())){
                payType=PayAuthType.two.value; 
            }
        }
       
        //返回处理码
        String procCode=personIdentifyManager.getIdentityLimitCheck(userId, orderAmt, payType,IntTxnCd._00100.value);
        if(!(ProcCodeConstants.PROC_CODE_200S1000.equals(procCode)))
            throw new WebException(procCode);
        
    }
    
    
}
